#include <iostream>
#include <string>
#include <functional>
#include <thread>
#include <chrono>
#include <mutex>

#include "DemoDateTime.h"
#include "DemoLambda.h"

using namespace std;

typedef struct {
    int timeInMS;
    TimerFuncWithArg timerFunc;
    void *funcDataPtr;
} DispatchAfterData;

void DispatchAfterLogic(DispatchAfterData *timmerData) {
    this_thread::sleep_for(chrono::milliseconds(timmerData->timeInMS));
    timmerData->timerFunc(timmerData->funcDataPtr);
}

std::thread * DispatchAfter(int timeInMS, TimerFuncWithArg timerFunc, void *funcDataPtr) {
    
    DispatchAfterData *timmerData = new DispatchAfterData;
    timmerData->timeInMS = timeInMS;
    timmerData->timerFunc = timerFunc;
    timmerData->funcDataPtr = funcDataPtr;
    
    std::thread* trd = new std::thread(DispatchAfterLogic, timmerData);
    return trd;
}

void DemoLambda(void) {
    cout<<endl<<endl<<"DemoLambda"<<endl;
    
    // https://www.jianshu.com/p/4af34e151d63
    
    
    //    lambda表达式的组成
    //    [=]/*1*/ ()/*2*/ mutable/*3*/ throw()/*4*/ -> int/*5*/ {}/*6*/
    //    1 capture子句
    //      [&]表示捕获的所有变量都是按照引用捕获的,lambda将会捕获所有在函数体中出现的外部变量.
    //      [=]表示捕获的所有变量都是按照值捕获的
    //      当需要访问类成员时,对于this的捕获比较特殊:
    //          当使用&方式时,捕获方式是&(this),即copy了this指针所指向的地址
    //          当使用=捕获时,捕获方式仍然是&(this)
    //          在c++11标准中, lambda只能捕获this指针地址,而不能对其所指的对象进行深拷贝.这往往导致线程安全问题
    //    2 参数列表(optional)
    //    3 可变规范(optional)
    //      lambda表达式默认其通过值捕获的变量都是const类型,即不可更改.当使用mutable关键字时可取消该特性.但是对变量的更改仅在lambda表达式函数体内生效.
    //    4 异常定义(optional)
    //    5 返回类型(optional)
    //    6 函数体
    
    
    //https://www.jb51.net/article/258665.htm
    int callTimes = 0;
    
    // 1  匿名调用
    [&](string name)
    {
        ++ callTimes;
        cout << "anonymous call " << endl;
        cout << "capture "<<callTimes<<", arg " << name << endl;
    }("zack");
    
    // 2 通过auto赋值
    auto fname = [=](string name) mutable
    {
        ++ callTimes;
        cout << "call as auto func var" << endl;
        cout << "capture "<<callTimes<<", arg "  << name << endl;
    };
    fname("Rolin");
    
    typedef void (*FuncWithName)(string name);
    // 3 函数指针
    FuncWithName fname2 = [](string name)
    {
        //++ callTimes;
        cout << "typedef call" << endl;
        cout << "arg "  << name << endl;
    };
    fname2("Vivo");
    
    // 4 function
    function<void(string)> funcName;
    funcName = [=](string name) mutable
    {
        ++ callTimes;
        cout << "call as std::function var" << endl;
        cout << "capture "<<callTimes<<", arg "  << name << endl;
    };
    funcName("Uncle Wang");
    
    logWs("befor timmer callTimes %d", callTimes);
    
    
    // 异步线程，延时执行器。
    std::thread * timmerThread = DispatchAfter(500,
                                    [](void *inputeData){
        logWs("timmer lambda begin ");
        int *cTimes = (int *)inputeData;
        *cTimes = *cTimes + 1;
        logWs("timmer lambda end ");
                                    },
                                    &callTimes);
    timmerThread->join();
    delete timmerThread;
    
    logWs("after timmer callTimes %d", callTimes);
    
}
